package br.ufpe.cin.mac.demo.ImageProcesser.client.gui;

/**
 * @(#)JAINetworkDemo.java	15.2 03/05/20
 *
 * Copyright (c) 2003 Sun Microsystems, Inc.
 * All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * -Redistribution in binary form must reproduct the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS
 * SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
 * USING, MODIFYING OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO
 * EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
 * OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN
 * IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that Software is not designed,licensed or intended for
 * use in the design, construction, operation or maintenance of any nuclear
 * facility.
 */

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.renderable.ParameterBlock;
import java.util.Hashtable;
import java.util.Vector;

import javax.media.jai.BorderExtender;
import javax.media.jai.Interpolation;
import javax.media.jai.InterpolationNearest;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTabbedPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import br.ufpe.cin.mac.demo.ImageProcesser.client.ICIcon;
import br.ufpe.cin.mac.demo.ImageProcesser.client.ICImageReader;
import br.ufpe.cin.mac.demo.ImageProcesser.server.IImageProServer;

class SourcePanel extends JPanel implements ListSelectionListener {

	ImageClientGUI demo;

	IImageProServer client;

	PlanarImage[] sources;

	int sourceNum;

	JLabel picture;

	Icon imageIcon;

	JList listOfImages;

	public SourcePanel(ImageClientGUI demo, String[] filenames,
			PlanarImage[] sources, int sourceNum, IImageProServer pClient) {

		this.demo = demo;
		this.sources = sources;
		this.sourceNum = sourceNum;
		this.client = pClient;

		Vector filenameList = new Vector();
		for (int i = 0; i < filenames.length; i++) {
			filenameList.add(filenames[i]);
		}

		// Create the list
		listOfImages = new JList(filenameList);
		listOfImages.setSelectedIndex(0);
		listOfImages.addListSelectionListener(this);

		// Put it in a scroll pane
		JScrollPane scrollPane = new JScrollPane(listOfImages);

		// Set up the picture label
		imageIcon = makeIcon(0);
		picture = new JLabel(imageIcon);
		Dimension size = new Dimension(imageIcon.getIconWidth(), imageIcon
				.getIconHeight());
		picture.setPreferredSize(size);

		// Put it in a scroll pane
		JScrollPane pictureScrollPane = new JScrollPane(picture,
				ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);

		setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
		add(scrollPane);
		add(Box.createHorizontalStrut(10));

		add(pictureScrollPane);
		setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

	}

	public void setListOfImages(int index) {
		listOfImages.setSelectedIndex(0);
	}

	public Icon makeIcon(int index) {
		float scale = 190.0F / Math.max(sources[index].getWidth(),
				sources[index].getHeight());
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(sources[index]);
		pb.add(scale);
		pb.add(scale);
		pb.add(0.0F);
		pb.add(0.0F);
		pb.add(new InterpolationNearest());

		PlanarImage scaled = client.create("scale", pb, null);
		return new ICIcon(scaled, client);
	}

	public void valueChanged(ListSelectionEvent e) {
		if (!e.getValueIsAdjusting()) {

			JList theList = (JList) e.getSource();
			int index = theList.getSelectedIndex();

			imageIcon = makeIcon(index);
			picture.setIcon(imageIcon);
			Dimension size = new Dimension(imageIcon.getIconWidth(), imageIcon
					.getIconHeight());
			picture.setPreferredSize(size);
			picture.revalidate();
			demo.setSourceIndex(sourceNum, index);
		}
	}

}

class SourceAdj extends ICGSourceAdjPanel implements ChangeListener {

	float xscale = 1.0F;

	float yscale = 1.0F;

	float xtrans = 0.0F;

	float ytrans = 0.0F;

	Interpolation interp;

	int srcId;

	JSlider xySlider;

	JSlider xTSlider;

	JSlider yTSlider;

	Vector sourceVec;

	ImageClientGUI demo;

	IImageProServer client;

	public SourceAdj(ImageClientGUI demo, int srcId, Vector sourceVec,
			IImageProServer pClient) {
		super(sourceVec);
		this.srcId = srcId;
		this.sourceVec = sourceVec;
		this.demo = demo;
		this.client = pClient;
		masterSetup();
	}

	public PlanarImage process() {

		PlanarImage im0 = getSource(srcId);

		ParameterBlock pb = new ParameterBlock();
		pb.addSource(im0);
		pb.add(xscale);
		pb.add(yscale);
		pb.add(xtrans);
		pb.add(ytrans);
		interp = Interpolation.getInstance(Interpolation.INTERP_NEAREST);
		pb.add(interp);

		PlanarImage img1 = client.create("scale", pb, renderHints);
		demo.setDyadicSource(img1, srcId);
		return img1;
	}

	public void reset() {
		xscale = yscale = 1.0F;
		interp = Interpolation.getInstance(Interpolation.INTERP_NEAREST);
		xySlider.setValue(0);
		xTSlider.setValue(0);
		yTSlider.setValue(0);
	}

	public void stateChanged(ChangeEvent e) {
		JSlider source = (JSlider) e.getSource();
		if (!(interp instanceof InterpolationNearest)
				&& source.getValueIsAdjusting()) {
			return;
		}
		int value = source.getValue();

		float fvalue = Math.abs(value) / 10.0F + 1.0F;
		if (value < 0) {
			fvalue = 1.0F / fvalue;
		}

		if (source == xySlider) {
			xySlider.setValue(value);
			xscale = yscale = fvalue;

		} else if (source == xTSlider) {
			xtrans = value;

		} else if (source == yTSlider) {
			ytrans = value;

		}
		repaint();
	}

	public void makeControls(JPanel controls) {

		xySlider = new JSlider(JSlider.HORIZONTAL, -40, 90, 0);
		xTSlider = new JSlider(JSlider.HORIZONTAL, -99, 99, 0);
		yTSlider = new JSlider(JSlider.HORIZONTAL, -99, 99, 0);

		Hashtable labels = new Hashtable();
		labels.put(new Integer(-40), new JLabel("1/5"));
		labels.put(new Integer(-30), new JLabel("1/4"));
		labels.put(new Integer(-20), new JLabel("1/3"));
		labels.put(new Integer(-10), new JLabel("1/2"));
		labels.put(new Integer(0), new JLabel("1"));
		labels.put(new Integer(10), new JLabel("2"));
		labels.put(new Integer(20), new JLabel("3"));
		labels.put(new Integer(30), new JLabel("4"));
		labels.put(new Integer(40), new JLabel("5"));
		labels.put(new Integer(50), new JLabel("6"));
		labels.put(new Integer(60), new JLabel("7"));
		labels.put(new Integer(70), new JLabel("8"));
		labels.put(new Integer(80), new JLabel("9"));
		labels.put(new Integer(90), new JLabel("10"));
		xySlider.setLabelTable(labels);
		xySlider.setPaintLabels(true);

		Hashtable labels1 = new Hashtable();

		labels1.put(new Integer(-100), new JLabel("-100"));
		labels1.put(new Integer(-75), new JLabel("-75"));
		labels1.put(new Integer(-50), new JLabel("-50"));
		labels1.put(new Integer(-25), new JLabel("-25"));
		labels1.put(new Integer(-10), new JLabel("-10"));
		labels1.put(new Integer(0), new JLabel("0"));
		labels1.put(new Integer(10), new JLabel("10"));
		labels1.put(new Integer(25), new JLabel("25"));
		labels1.put(new Integer(50), new JLabel("50"));
		labels1.put(new Integer(75), new JLabel("75"));
		labels1.put(new Integer(100), new JLabel("100"));

		xTSlider.setLabelTable(labels1);
		xTSlider.setPaintLabels(true);

		yTSlider.setLabelTable(labels1);
		yTSlider.setPaintLabels(true);

		JPanel xySliderPanel = new JPanel();
		xySliderPanel.setLayout(new GridLayout(0, 1));

		JLabel xyLabel = new JLabel("X/Y Scale",
				(int) Component.CENTER_ALIGNMENT);
		xySliderPanel.add(xyLabel);
		xySliderPanel.add(xySlider);

		JPanel xTSliderPanel = new JPanel();
		xTSliderPanel.setLayout(new GridLayout(0, 1));

		JLabel xTLabel = new JLabel("X Translate",
				(int) Component.CENTER_ALIGNMENT);
		xTLabel.setPreferredSize(xyLabel.getPreferredSize());
		xTSliderPanel.add(xTLabel);
		xTSliderPanel.add(xTSlider);

		JPanel yTSliderPanel = new JPanel();
		yTSliderPanel.setLayout(new GridLayout(0, 1));

		JLabel yTLabel = new JLabel("Y Translate",
				(int) Component.CENTER_ALIGNMENT);
		yTLabel.setPreferredSize(xyLabel.getPreferredSize());
		yTSliderPanel.add(yTLabel);
		yTSliderPanel.add(yTSlider);

		xySlider.addChangeListener(this);
		xTSlider.addChangeListener(this);
		yTSlider.addChangeListener(this);
		JPanel sliderPanel = new JPanel();
		sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.Y_AXIS));

		sliderPanel.add(xySliderPanel);
		sliderPanel.add(xTSliderPanel);
		sliderPanel.add(yTSliderPanel);
		sliderPanel.setLayout(new GridLayout(0, 1));
		controls.setLayout(new BorderLayout());
		controls.add("Center", sliderPanel);

	}
}

class CachePanel extends JPanel implements ActionListener, ChangeListener {

	ImageClientGUI demo;

	private static final int TILE_CACHE_MBYTES_PER_TICK = 4;

	private static final int TILE_CACHE_BYTES_PER_TICK = TILE_CACHE_MBYTES_PER_TICK * 1024 * 1024;

	public CachePanel(ImageClientGUI demo) {
		this.demo = demo;

		setLayout(new GridLayout(4, 1));

		add(new JLabel(""));

		JButton flushButton = new JButton("Flush Tile Cache");
		add(flushButton);
		flushButton.addActionListener(this);

		JLabel capacityLabel = new JLabel("Tile Cache Capacity",
				SwingConstants.CENTER);
		add(capacityLabel);

		long cacheCapacity = JAI.getDefaultInstance().getTileCache()
				.getMemoryCapacity();
		int capacity = (int) (cacheCapacity / TILE_CACHE_BYTES_PER_TICK);
		JSlider capacitySlider = new JSlider(JSlider.HORIZONTAL, 0, 16,
				capacity);
		Hashtable labels = new Hashtable();
		for (int i = 0; i <= 16; i += 4) {
			labels.put(new Integer(i), new JLabel(
					(i * TILE_CACHE_MBYTES_PER_TICK) + "M"));
		}
		capacitySlider.setLabelTable(labels);
		capacitySlider.setPaintLabels(true);
		capacitySlider.setMajorTickSpacing(2);
		capacitySlider.setMinorTickSpacing(1);
		capacitySlider.setPaintTicks(true);
		capacitySlider.setSnapToTicks(true);

		add(capacitySlider);
		capacitySlider.addChangeListener(this);
	}

	public void actionPerformed(ActionEvent e) {
		JAI.getDefaultInstance().getTileCache().flush();
	}

	public void stateChanged(ChangeEvent e) {
		JSlider source = (JSlider) e.getSource();
		if (source.getValueIsAdjusting()) {
			return;
		}

		long capacity = source.getValue() * TILE_CACHE_BYTES_PER_TICK;
		JAI.getDefaultInstance().getTileCache().setMemoryCapacity(capacity);
	}
}

class HintPanel extends JPanel implements ItemListener {

	static final String[] extenderLabels = { "No Border Extension",
			"Extend borders with zeros", "Extend borders by copying edges",
			"Extend borders by reflection", "Extend borders by wrapping" };

	static final BorderExtender[] extenders = { null,
			BorderExtender.createInstance(BorderExtender.BORDER_ZERO),
			BorderExtender.createInstance(BorderExtender.BORDER_COPY),
			BorderExtender.createInstance(BorderExtender.BORDER_REFLECT),
			BorderExtender.createInstance(BorderExtender.BORDER_WRAP) };

	static final RenderingHints.Key extenderKey = JAI.KEY_BORDER_EXTENDER;

	ImageClientGUI demo;

	RenderingHints renderHints = null;

	public HintPanel(ImageClientGUI demo) {
		this.demo = demo;

		JComboBox extenderBox = new JComboBox();
		for (int i = 0; i < extenderLabels.length; i++) {
			extenderBox.addItem(extenderLabels[i]);
		}
		extenderBox.addItemListener(this);

		add(extenderBox);
	}

	public void itemStateChanged(ItemEvent e) {
		if (e.getStateChange() == ItemEvent.DESELECTED) {
			return;
		}

		String item = (String) e.getItem();
		for (int i = 0; i < extenderLabels.length; i++) {
			if (item.equals(extenderLabels[i])) {
				if (i == 0) {
					renderHints = null;
				} else {
					renderHints = new RenderingHints(extenderKey, extenders[i]);
				}
			}
		}

		demo.setRenderingHints(renderHints);
	}
}

public class ImageClientGUI extends WindowAdapter implements ChangeListener {

	JFrame frame;

	ICGDemoPanel currPanel = null;

	ICGDemoPanel[] panels;

	ICGSourceAdjPanel srcAdjPanel, srcAdjPanel0;

	SourcePanel sourcePanel, sourcePanel1;

	int numPanels;

	int numMonadicPanels;

	JTabbedPane srcTabbedPane;

	JTabbedPane mainTabbedPane;

	JTabbedPane dyadicTabbedPane;

	PlanarImage[] sources;

	RenderingHints renderHints = null;

	String imagePath;

	IImageProServer client;

	public ImageClientGUI(String imagePath, IImageProServer proxy) {
		// Create a top-level frame to hold the demo
		frame = new JFrame("JAI Network Imaging Demo");
		
		this.imagePath = imagePath;
		this.client = proxy;
		

		String[] filenames = null, fullnames = null;
		try {
			filenames = client.getDirectoryListing(imagePath);
			fullnames = client.getPathDirectoryAbsoluteListing(imagePath);
		} catch (Exception re) {
			System.out.println(re.getMessage());
			re.printStackTrace();
		}

		// Read in the images on the server
		sources = new PlanarImage[filenames.length];
		for (int i = 0; i < fullnames.length; i++) {
			sources[i] = ICImageReader.readImage(fullnames[i], client);
		}
		
		if(sources.length == 0){
			System.err.println("No imagens on server\nExit\n");
			System.exit(0);
		}
		Vector<PlanarImage> sourceVec = new Vector<PlanarImage>();
		
		sourceVec.add(sources[0]);
		sourceVec.add(sources[0]);

		// Create a panel for tile cache control.
		JPanel cachePanel = new CachePanel(this);

		JPanel hintPanel = new HintPanel(this);

		JPanel extraPanel = new JPanel();
		extraPanel.setLayout(new GridLayout(2, 1));
		extraPanel.add(cachePanel);
		extraPanel.add(hintPanel);

		JPanel controlPanel = new JPanel();
		controlPanel.setLayout(new BorderLayout());

		controlPanel.add("East", extraPanel);

		frame.getContentPane().add("North", controlPanel);

		// Instantiate panels for each operation to be demonstrated.
		// New operation panels should be added here.
		numPanels = 0;
		panels = new ICGDemoPanel[16];
		panels[numPanels++] = new ICGScalePanel(sourceVec, client);
		panels[numPanels++] = new ICGRotatePanel(sourceVec, client);
		panels[numPanels++] = new ICGConvolvePanel(sourceVec, client);
		panels[numPanels++] = new ICGAddConstPanel(sourceVec, client);
		panels[numPanels++] = new ICGTransposePanel(sourceVec, client);
		panels[numPanels++] = new ICGBlurSharpPanel(sourceVec, client);
		panels[numPanels++] = new ICGGradientPanel(sourceVec, client);
		panels[numPanels++] = new ICGMedianPanel(sourceVec, client);
		numMonadicPanels = numPanels;

		currPanel = panels[0];

		// Dyadic ops
		panels[numPanels++] = new ICGDyadicSource0Panel(this, sourceVec, client);
		panels[numPanels++] = new ICGDyadicSource1Panel(this, sourceVec, client);
		panels[numPanels++] = new ICGDyadicAddPanel(this, sourceVec, client);
		panels[numPanels++] = new ICGDyadicSubtractPanel(this, sourceVec,
				client);
		panels[numPanels++] = new ICGDyadicMultiplyPanel(this, sourceVec,
				client);
		panels[numPanels++] = new ICGDyadicDividePanel(this, sourceVec, client);

		// Create a panel for source selection.
		sourcePanel = new SourcePanel(this, filenames, sources, 0, client);
		sourcePanel1 = new SourcePanel(this, filenames, sources, 1, client);
		srcAdjPanel0 = new SourceAdj(this, 0, sourceVec, client);
		srcAdjPanel = new SourceAdj(this, 1, sourceVec, client);

		srcTabbedPane = new JTabbedPane();
		srcTabbedPane.add("Source0", sourcePanel);
		srcTabbedPane.add("Source1", sourcePanel1);
		srcTabbedPane.add("Source0 Adj", srcAdjPanel0);
		srcTabbedPane.add("Source1 Adj", srcAdjPanel);
		srcTabbedPane.setEnabledAt(1, false);
		srcTabbedPane.setEnabledAt(2, false);
		srcTabbedPane.setEnabledAt(3, false);

		srcTabbedPane.setPreferredSize(new Dimension(600, 300));
		srcTabbedPane.addChangeListener(this);
		controlPanel.add("Center", srcTabbedPane);

		// Insert the operation panels into a tabbed pane.
		mainTabbedPane = new JTabbedPane();
		for (int i = 0; i < numMonadicPanels; i++) {
			mainTabbedPane.add(panels[i].getDemoName(), panels[i]);
		}

		dyadicTabbedPane = new JTabbedPane();
		for (int i = numMonadicPanels; i < numPanels; i++) {
			dyadicTabbedPane.add(panels[i].getDemoName(), panels[i]);
		}

		mainTabbedPane.add("Dyadic", dyadicTabbedPane);
		mainTabbedPane.setPreferredSize(new Dimension(800, 450));
		frame.getContentPane().add("Center", mainTabbedPane);
		mainTabbedPane.addChangeListener(this);
		dyadicTabbedPane.addChangeListener(this);

		// Pack the frame and make it visible.
		frame.pack();
		frame.setVisible(true);
		frame.addWindowListener(this);
	}

	public void stateChanged(ChangeEvent e) {
		JTabbedPane pane = (JTabbedPane) e.getSource();
		int index = pane.getSelectedIndex();

		if (pane == mainTabbedPane) {
			currPanel.deactivate();
			enableSource1(false);
			if (index >= numMonadicPanels) {
				currPanel = panels[dyadicTabbedPane.getSelectedIndex()
						+ numMonadicPanels];
				enableSource1(true);
			} else {
				currPanel = panels[index];
			}
			currPanel.activate();
		} else if (pane == dyadicTabbedPane) {
			currPanel.deactivate();
			currPanel = panels[index + numMonadicPanels];
			currPanel.activate();
		}
	}

	/** 
	 * Sets the index of one of the sources in response to an
	 * event in one of the source selector panels.
	 */

	public void setSourceIndex(int sourceNum, int index) {
		for (int i = 0; i < numPanels; i++) {
			panels[i].setSource(sourceNum, sources[index]);
		}
		srcAdjPanel.setSource(sourceNum, sources[index]);
		srcAdjPanel0.setSource(sourceNum, sources[index]);
	}

	public void setDyadicSource(PlanarImage img, int index) {
		for (int i = numMonadicPanels; i < numPanels; i++) {
			panels[i].setSource(index, img);
		}
	}

	public void resetAdj() {
		srcAdjPanel0.reset();
		srcAdjPanel.reset();
	}

	public void enableSource1(boolean isSet) {
		srcTabbedPane.setEnabledAt(1, isSet);
		srcTabbedPane.setEnabledAt(2, isSet);
		srcTabbedPane.setEnabledAt(3, isSet);
		srcTabbedPane.setSelectedIndex(0);
	}

	public void setRenderingHints(RenderingHints renderHints) {
		this.renderHints = renderHints;
		for (int i = 0; i < numPanels; i++) {
			panels[i].setRenderingHints(renderHints);
		}
	}

	public void windowClosing(WindowEvent e) {
		System.exit(0);
	}
}
